package summary;

import java.util.Iterator;
import java.util.Vector;

public class InstantStatistics {
	public static final int LINE = 0;
	public static final int RING = 1;
	
	public long second;
	
	public long maxLocalSkew;
	public long maxGlobalSkew;
	public long avgLocalSkew;
	public long avgGlobalSkew;
	
	Vector<NodeStatistics> nodeStatistics = null;

	public InstantStatistics(InstantData data,int topology) {
		
		nodeStatistics = new Vector<NodeStatistics>();
		calculateSkews(data.getData(),topology);		
		
		this.maxLocalSkew = 0;
		this.avgLocalSkew = 0;
		this.maxGlobalSkew = 0;
		this.avgGlobalSkew = 0;
		
		summary();
		
		this.second = data.second;
	}
	
	public void setNodeSkews(Vector<NodeStatistics> skews){
		nodeStatistics = skews;
	}
	
	public Vector<NodeStatistics> getNodeSkews(){
		return nodeStatistics;
	}
	
	private void calculateSkews(Vector<NodeData> nodes,int topology){
			
		for (Iterator<NodeData> iterator = nodes.iterator(); iterator.hasNext();) {
			NodeData nodeData = (NodeData) iterator.next();
			
			long global = calculateGlobalSkew(nodeData, nodes);
			long local = calculateLocalSkew(nodeData, nodes, topology);
			
			NodeStatistics info = new NodeStatistics(nodeData.id, local, global);
			nodeStatistics.add(info);
		}
	}
	
	private long calculateGlobalSkew(NodeData node, Vector<NodeData> nodes){
		
		long global = 0;
		
		for (Iterator<NodeData> iterator = nodes.iterator(); iterator.hasNext();) {
			NodeData nodeToCompare = (NodeData) iterator.next();
			
			long diff = Math.abs(node.clock-nodeToCompare.clock); 
			
			if(diff > 0xF0000000L){
				long result = 0x0FFFFFFFFL;
				
				if(nodeToCompare.clock > node.clock){
					result -= nodeToCompare.clock;
					result += node.clock;		
				}
				else{
					result -= node.clock;
					result += nodeToCompare.clock;
				}
								
				diff = result;
			}
						
			if(diff > global){
				global = diff; 
			}
		}
		
		return global;
	}
	
	private long calculateLocalSkew(NodeData node, Vector<NodeData> nodes,int topology){
		
		long local = 0;
		
		for (Iterator<NodeData> iterator = nodes.iterator(); iterator.hasNext();) {
			NodeData nodeToCompare = (NodeData) iterator.next();
						
			boolean isNeighbor = false;
			
			if((node.id == (nodeToCompare.id + 1) )||(node.id == (nodeToCompare.id - 1) )){
				isNeighbor = true;
			}
			else if(topology == RING){
				if(nodes.firstElement().equals(node)){
					if(nodes.lastElement().equals(nodeToCompare)){
						isNeighbor = true;
					}
				}
				else if(nodes.lastElement().equals(node)){
					if(nodes.firstElement().equals(nodeToCompare)){
						isNeighbor = true;
					}
				}
			}
			
			if(isNeighbor) {
				long diff = Math.abs(node.clock-nodeToCompare.clock); 
				
				if(diff > 40000000L){
					long result = 0x0FFFFFFFFL;
					result -= node.clock;
					result += nodeToCompare.clock;				
					diff = result;
				}
				
				if(diff > 40000000L){
					long result = 0x0FFFFFFFFL;
					result -= nodeToCompare.clock;
					result += node.clock;				
					diff = result;
				}
				
				if(diff > local){
					local = diff; 
				}	
			}
		}
		
		return local;
	}
	
	private void summary(){
		long sumGlobal = 0;
		long sumLocal = 0;
		
		for (Iterator<NodeStatistics> iterator = nodeStatistics.iterator(); iterator.hasNext();) {
			NodeStatistics node = (NodeStatistics) iterator.next();
			
			if(node.globalSkew > maxGlobalSkew){
				maxGlobalSkew = node.globalSkew;
			}
			
			sumGlobal += node.globalSkew;
			
			if(node.localSkew > maxLocalSkew){
				maxLocalSkew = node.localSkew;
			}
			
			sumLocal += node.localSkew;				
		}
		
		this.avgLocalSkew = sumLocal / nodeStatistics.size();
		this.avgGlobalSkew = sumGlobal / nodeStatistics.size();
	}
}
